//@author A0105740R
package rightnow.parser;

import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;

import rightnow.util.DateTimeFormatters;

/**
 * This class contains DateTime parsers.<br>
 * This class also provides various 
 * regular expressions that can be used to mark up supported date time string.
 */
public class DateTimeParsers {
	public static final String TIME_REGEX = 
			"((1[0-2]|[1-9])(:([0-5][0-9]))?\\s*(AM|am|PM|pm))"
			+ "|(([0-1]?[0-9]|[2][0-3]):([0-5][0-9]))";
	private static final String TIME_24_REGEX = 
			"([0-1]?[0-9]|[2][0-3]):([0-5][0-9])";
	private static final String TIME_12_LONG_REGEX = 
			"(1[0-2]|[1-9]):([0-5][0-9])\\s*(AM|am|PM|pm)";
	private static final String TIME_12_SHORT_REGEX = 
			"(1[0-2]|[1-9])\\s*(AM|am|PM|pm)";
	
	/* 
	 * This is an approximate form for standard date, the string marked by this
	 * regular expression should be checked by DateTime Formatter later.
	 */
	public static final String APPROX_STD_DATE_REGEX = 
			"(\\d+[-/.]\\d+[-/.]\\d+)"
			+ "|(\\d+\\s*(([Jj]an(uary)?)|([Ff]eb(uary)?)|([Mm]ar(ch)?)"
			+ "|([Aa]pr(il)?)|([Mm]ay)|([Jj]une?)|([Jj]uly?)|([Aa]ug(ust)?)"
			+ "|([Ss]ep(tember)?)|([Oo]ct(ober)?)|([Nn]ov(ember)?)"
			+ "|([Dd]ec(ember)?))\\s*\\d*)";
	
	private static final String DATE_STD_NO_TEXT_REGEX = 
			"\\d+[-/.]\\d+[-/.]\\d+";
	private static final String DATE_STD_TEXT_LONG_ANA_REGEX = 
			"\\d+\\s*([A-Z]|[a-z])+\\s*\\d+";
	private static final String DATE_STD_TEXT_SHORT_ANA_REGEX = 
			"\\d+\\s*([A-Z]|[a-z])+";
	
	public static final String WEEKDAY_REGEX = 
			"\\b([Mm]on(day)?)|([Tt]ue(sday)?)|([Ww]ed(nesday)?)"
			+ "|([Tt]hu(rsday)?)|([Ff]ri(day)?)|([Ss]at(urday)?)"
			+ "|([Ss]un(day)?)\\b";
	
	public static final String TMR_YESTERDAY_REGEX = 
			"\\b([Tt](mr|omorrow))|([Tt]oday)|([Yy]esterday)\\b";
	
	private static final String TMR_REGEX = "[Tt](mr|omorrow)";
	private static final String TODAY_REGEX = "[Tt]oday";
	private static final String YESTERDAY_REGEX = "[Yy]esterday";
	
	/**
	 * @param text Supported time formats are HH:mm, HH aa, HH:mm aa.<br>
	 * 			See JAVA8 DateTimeFormatter for the meaning of the symbols used.
	 * @return null if not parsed successfully
	 */
	public static LocalTime parseTime(String text) {
		if (text.matches(TIME_12_SHORT_REGEX)) {
			text = text.replaceAll("\\s", "");
			try {
				return DateTimeFormatters.
						time12ShortFormatter.parseLocalTime(text);
			}
			catch (IllegalArgumentException e) {
				return null;
			}
		}
		else if (text.matches(TIME_12_LONG_REGEX)) {
			text = text.replaceAll("\\s", "");
			try {
				return DateTimeFormatters.
						time12LongFormatter.parseLocalTime(text);
			}
			catch (IllegalArgumentException e) {
				return null;
			}
		}
		else if (text.matches(TIME_24_REGEX)) {
			try {
				return DateTimeFormatters.time24Formatter.parseLocalTime(text);
			}
			catch (IllegalArgumentException e) {
				return null;
			}
		}
		
		return null;
	}
	
	/**
	 * @param text Supported date formats are dd/MM/yyyy, dd-MM-yyyy, 
	 * 			dd.MM.yyyy, dd LLL yyyy, dd LLL.<br>
	 *	 		See JAVA8 DateTimeFormatter for the meaning of the symbols used.
	 * @return null if not parsed successfully
	 */
	public static LocalDate parseStdDate(String text) {
		if (text.matches(DATE_STD_NO_TEXT_REGEX)) {
			text = text.replaceAll("[-.]", "/");
			try {
				return DateTimeFormatters.stdDateFormatter.parseLocalDate(text);
			}
			catch (IllegalArgumentException e) {
				return null;
			}
		}
		else if (text.matches(DATE_STD_TEXT_LONG_ANA_REGEX)) {
			text = text.replaceAll("\\s", "");
			try {
				return DateTimeFormatters.
						stdDateTextLongFormatter.parseLocalDate(text);
			}
			catch (IllegalArgumentException e) {
				return null;
			}
		}
		else if (text.matches(DATE_STD_TEXT_SHORT_ANA_REGEX)) {
			text = text.replaceAll("\\s", "");
			try {
				return DateTimeFormatters.stdDateTextShortFormatter.
						parseLocalDate(text).
						withYear(DateTime.now().getYear());
			}
			catch (IllegalArgumentException e) {
				return null;
			}
		}
		return null;
	}
	
	/**
	 * @param text Supported date format is EEE.<br>
	 * 		See JAVA8 DateTimeFormatter for the meaning of the symbol used.
	 * @return null if not parsed successfully
	 */
	public static LocalDate parseWeekDay(String text) {
		try {
			return DateTime.now().withDayOfWeek(
					DateTimeFormatters.weekdayFormatter.
					parseLocalDate(text).getDayOfWeek()).toLocalDate();
		}
		catch (IllegalArgumentException e) {
			return null;
		}
	}
	
	/**
	 * @param text Supported texts are yesterday, today, tomorrow, tmr.
	 * @return null if not parsed successfully
	 */
	public static LocalDate parseTmrYesterday(String text) {
		if (text.matches(TMR_REGEX)) {
			return DateTime.now().plusDays(1).toLocalDate();
		}
		else if (text.matches(TODAY_REGEX)) {
			return DateTime.now().toLocalDate();
		}
		else if (text.matches(YESTERDAY_REGEX)) {
			return DateTime.now().plusDays(-1).toLocalDate();
		}
		else {
			return null;
		}
	}
}
